package com.barneyx.mshinfoplatform.util;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.barneyx.mshinfoplatform.common.ExResult;
import com.barneyx.mshinfoplatform.common.SmsUtil;
import com.barneyx.mshinfoplatform.entity.enums.EPlatformType;
import com.barneyx.mshinfoplatform.entity.enums.ESex;
import com.barneyx.mshinfoplatform.entity.enums.EUserState;
import com.barneyx.mshinfoplatform.entity.user.PlatformUserInfo;
import com.barneyx.mshinfoplatform.entity.user.UserBindPhone;
import com.barneyx.mshinfoplatform.entity.user.UserEntity;
import com.barneyx.mshinfoplatform.entity.user.UserPlatformEntity;
import com.barneyx.mshinfoplatform.exception.UserException;
import com.barneyx.mshinfoplatform.service.user.IUserPlatformService;
import com.barneyx.mshinfoplatform.service.user.IUserService;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

import java.util.List;
import java.util.stream.Collectors;

import static com.barneyx.mshinfoplatform.common.ExResult.ResponseCode.*;

@Component
public class UserUtil {
    @Resource
    private IUserService userService;

    @Resource
    private IUserPlatformService userPlatformService;

    @Resource
    private WxMpService wxMpService;


    @Resource
    private SmsUtil smsUtil;

    /**
     * 微信公众平台JSSDK创建签名
     *
     * @param url
     * @return
     */
    public WxJsapiSignature JsCreateSignature(String url) {
        try {
            return wxMpService.createJsapiSignature(url);
        } catch (WxErrorException ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 获取当前登陆用户信息|必须是注册的,没有实名或是没有完善资料都将异常!
     *
     * @return
     * @throws UserException
     */
    public UserPlatformEntity getCurrentLoginMastUserInfo() throws UserException {
        try {
            String platform_info_id = StpUtil.getLoginIdAsString();
            if (platform_info_id == null) throw new UserException(USER_NOT_LOGIN_ERROR);
            UserPlatformEntity user_platform_info = userPlatformService.getById(platform_info_id);
            if (user_platform_info == null) throw new UserException(ACCESS_DENIED);
            if (user_platform_info.getUserId().isBlank()) throw new UserException(USER_NOT_AUTHENTICATION_ERROR);
            UserEntity user_info = userService.getById(user_platform_info.getUserId());
            if (user_info == null) throw new UserException(ERROR);
            user_platform_info.setUser(user_info);
            return user_platform_info;
        } catch (UserException ex) {
            throw new UserException(ex.getCode());
        }
    }

    public UserPlatformEntity getCurrentLoginUserInfo() throws UserException {
        try {
            String platform_info_id = StpUtil.getLoginIdAsString();
            if (StrUtil.isBlank(platform_info_id)) throw new UserException(ACCESS_DENIED);
            UserPlatformEntity user_platform_info = userPlatformService.getById(platform_info_id);
            if (user_platform_info == null) throw new UserException(ACCESS_DENIED);
            UserEntity user_info = userService.getById(user_platform_info.getUserId());
            if (user_info != null) user_platform_info.setUser(user_info);
            return user_platform_info;
        } catch (UserException ex) {
            throw new UserException(ex.getCode());
        }
    }

    /**
     * 获取当前登陆的所有平台UserIds
     *
     * @return
     * @throws UserException
     */

    public List<String> getUserIds() throws UserException {
        try {
            String platform_login_id = StpUtil.getLoginIdAsString();
            UserPlatformEntity user_platfrom_info = userPlatformService.getById(platform_login_id);
            if (user_platfrom_info == null) throw new UserException(ACCESS_DENIED);
            List<UserPlatformEntity> other_platform_users = userPlatformService.list(new LambdaQueryWrapper<UserPlatformEntity>()
                    .eq(UserPlatformEntity::getUserId, user_platfrom_info.getUserId()));
            if (other_platform_users.isEmpty()) throw new UserException(ACCESS_USER_LOCK);
            return other_platform_users.stream().map(UserPlatformEntity::getUserPlatformId).collect(Collectors.toList());
        } catch (UserException ex) {
            throw new UserException(ex.getCode());
        }
    }

    /**
     * 获取指定用户的所有平台ids
     *
     * @param platformUserid
     * @return
     * @throws UserException
     */
    public List<String> getUserPlatformIds(String platformUserid) throws UserException {
        try {
            UserPlatformEntity user_platfrom_info = userPlatformService.getById(platformUserid);
            if (user_platfrom_info == null) throw new UserException(USER_INFO_NOT_FOUND_ERROR);
            List<UserPlatformEntity> other_platform_users = userPlatformService.list(new LambdaQueryWrapper<UserPlatformEntity>()
                    .eq(UserPlatformEntity::getUserId, user_platfrom_info.getUserId()));
            if (other_platform_users.isEmpty()) throw new UserException(ACCESS_USER_LOCK);
            return other_platform_users.stream().map(UserPlatformEntity::getUserPlatformId).collect(Collectors.toList());
        } catch (UserException ex) {
            throw new UserException(ex.getCode());
        }
    }

    /**
     * 判断当前微信用户是否关注公众号
     *
     * @param openId
     * @return
     */
    public boolean getUserSubscribe(String openId) throws WxErrorException {
        WxMpUser wxMpUser = wxMpService.getUserService().userInfo(openId);
        return wxMpUser.getSubscribe();
    }


    public PlatformUserInfo getUserInfoByWeChatCode(String code) throws UserException {
        try {
            WxOAuth2AccessToken accessToken = wxMpService.getOAuth2Service().getAccessToken(code);
            WxOAuth2UserInfo userInfo = wxMpService.getOAuth2Service().getUserInfo(accessToken, "zh_CN");
//            WxMpUser wxMpUser = wxMpService.getUserService().userInfo(userInfo.getOpenid());

            if (userInfo == null) throw new UserException(USER_LOGIN_ERROR);

            UserPlatformEntity userPlatformInfo = userPlatformService.getOne(new LambdaQueryWrapper<UserPlatformEntity>()
                    .eq(UserPlatformEntity::getOpenId, userInfo.getOpenid()));

            //如果没有注册
            if (userPlatformInfo == null) {
                userPlatformInfo = new UserPlatformEntity();
                userPlatformInfo.setNickName(userInfo.getNickname());
                userPlatformInfo.setUserId(null);
                userPlatformInfo.setPhone(null);
                userPlatformInfo.setSex(userInfo.getSex() == 1 ? ESex.MEN : ESex.LADY);
                userPlatformInfo.setPlatformIdentification(EPlatformType.WECHAT_H5);
                userPlatformInfo.setVia(userInfo.getHeadImgUrl());
                userPlatformInfo.setUnionId(userInfo.getUnionId());
                userPlatformInfo.setToken(SecureUtil.md5(userInfo.getOpenid()));
                userPlatformInfo.setOpenId(userInfo.getOpenid());
                boolean save = userPlatformService.save(userPlatformInfo);
                if (!save) throw new UserException(USER_LOGIN_ERROR);
            }
            StpUtil.login(userPlatformInfo.getUserPlatformId(), EPlatformType.WECHAT_H5.getValue());
            UserEntity user_info = userService.getById(userPlatformInfo.getUserId());
            if (user_info != null) userPlatformInfo.setUser(user_info);
            return PlatformUserInfo.builder()
                    .PlatformUser(userPlatformInfo)
                    .Device(EPlatformType.WECHAT_H5)
                    .User(user_info)
                    .build();
        } catch (WxErrorException ex) {
            throw new UserException(USER_WECHAT_MP_LOGIN_ERROR);
        }
    }


    public boolean VerifyUserPhoneCode(UserBindPhone userBindPhone) throws UserException {
        String validPhone = smsUtil.getValidPhone(userBindPhone.getPhone().trim());
        if (StrUtil.isBlank(validPhone)) throw new UserException(USER_BIND_CODE_OR_PHONE_ERROR);
        return true;
    }


    public UserPlatformEntity getUserPlatform(String userPlatfomrId) throws UserException {
        UserPlatformEntity user_platform = userPlatformService.getById(userPlatfomrId);
        if (user_platform == null) throw new UserException(USER_LOGIN_ERROR);
        UserEntity user_info = userService.getById(user_platform.getUserId());
        if (user_info == null) throw new UserException(USER_LOGIN_ERROR);
        user_platform.setUser(user_info);
        return user_platform;
    }

    public UserEntity getUserById(String userId) {
        return userService.getById(userId);
    }

    /**
     * 绑定平台和用户-手机
     *
     * @param userBindPhone
     * @return
     * @throws UserException
     */
    @Transactional
    public UserPlatformEntity bindPlatformAndUser(UserBindPhone userBindPhone) throws UserException {
        VerifyUserPhoneCode(userBindPhone);

        String loginId = StpUtil.getLoginIdAsString();
//        String loginDevice = StpUtil.getLoginDevice();

        UserPlatformEntity userPlatformInfo = userPlatformService.getById(loginId);
        if (userPlatformInfo == null) throw new UserException(ExResult.ResponseCode.ERROR);


        if (StrUtil.isBlank(userPlatformInfo.getPhone())) {
            userPlatformInfo.setPhone(userBindPhone.getPhone().trim());
            boolean update = userPlatformService.update(new LambdaUpdateWrapper<UserPlatformEntity>()
                    .eq(UserPlatformEntity::getUserPlatformId, userPlatformInfo.getUserPlatformId())
                    .set(UserPlatformEntity::getPhone, userBindPhone.getPhone().trim()));
            if (!update) throw new UserException(USER_UPDATE_PLATFORM_INFO_ERROR);


            UserEntity user_Info = userService.getOne(new LambdaQueryWrapper<UserEntity>()
                    .eq(UserEntity::getUserPhone, userBindPhone.getPhone().trim()));

            if (user_Info == null) {
                user_Info = new UserEntity()
                        .setUserPhone(userBindPhone.getPhone().trim())
                        .setUserPwd("msh" + userBindPhone.getPhone().trim())
                        .setUserNickName("慢生活用户")
                        .setUserName(userBindPhone.getPhone().trim())
                        .setUserSex(ESex.OTHER)
                        .setIsLock(false)
                        .setIsVip(false)
                        .setState(EUserState.NONE);
                boolean save = userService.save(user_Info);
                if (!save) throw new UserException(USER_REGISTER_ERROR);


                userPlatformInfo.setUserId(user_Info.getUserId());
                userPlatformService.update(new LambdaUpdateWrapper<UserPlatformEntity>()
                        .eq(UserPlatformEntity::getUserPlatformId, userPlatformInfo.getUserPlatformId())
                        .set(UserPlatformEntity::getUserId, user_Info.getUserId()));

            }
            userPlatformInfo.setUser(user_Info);
            return userPlatformInfo;
        } else {
            userPlatformInfo.setUser(this.getUserById(userPlatformInfo.getUserId()));
            return userPlatformInfo;
        }
    }


    public UserEntity H5Login(String username, String userPwd) throws UserException {
        UserEntity user_info = userService.getOne(new LambdaQueryWrapper<UserEntity>()
                .eq(UserEntity::getUserName, username)
                .or(c -> c.eq(UserEntity::getUserPhone, username))
                .eq(UserEntity::getUserPwd, userPwd));
        if (user_info == null) throw new UserException(USER_LOGIN_ERROR);
        if (user_info.getState() == EUserState.LOCK) throw new UserException(ACCESS_USER_LOCK);
        return user_info;
    }

    public UserPlatformEntity H5PlatformLogin(String userId, EPlatformType divceType) {
        UserPlatformEntity h5_platform_info = userPlatformService.getOne(new LambdaQueryWrapper<UserPlatformEntity>()
                .eq(UserPlatformEntity::getUserId, userId.trim())
                .eq(UserPlatformEntity::getPlatformIdentification, divceType));
        return h5_platform_info;
    }

    //创建H5平台用户
    public UserPlatformEntity createOrUpdateH5Info(String userName, String userPwd) throws UserException {
        UserEntity user_info = this.H5Login(userName, userPwd);
        UserPlatformEntity user_platform_info = this.H5PlatformLogin(user_info.getUserId(), EPlatformType.H5);
        if (user_platform_info == null) {
            user_platform_info = new UserPlatformEntity();
            user_platform_info.setPlatformIdentification(EPlatformType.H5);
            user_platform_info.setUserId(user_info.getUserId());
            user_platform_info.setName(user_info.getUserName());
            user_platform_info.setNickName(user_info.getUserNickName());
            user_platform_info.setOpenId(SecureUtil.md5(user_info.getUserId() + user_info.getUserPhone()));
            user_platform_info.setToken(SecureUtil.md5(user_info.getUserId()));
            user_platform_info.setPhone(user_info.getUserPhone());
            user_platform_info.setSex(user_info.getUserSex());
            user_platform_info.setVia(user_info.getUserVia());
            boolean save = userPlatformService.save(user_platform_info);
            if (!save) throw new UserException(ERROR);
            user_platform_info.setUser(user_info);
        }

        StpUtil.login(user_platform_info.getUserPlatformId(), EPlatformType.H5.getValue());
        return user_platform_info.setUser(user_info);
    }

    /**
     * 判断当前用户是否登录，如果登录了，返回用户的登录Id
     *
     * @return
     * @throws UserException
     */
    public String checkLogin() throws UserException {
        String platfomr_login_id = StpUtil.getLoginIdAsString();
        if (platfomr_login_id == null) throw new UserException(USER_NOT_LOGIN_ERROR);
        return platfomr_login_id;
    }

    /**
     * 更新用户当前平台信息
     *
     * @param userPlatform
     * @return
     * @throws UserException
     */
    public boolean updatePlatfomrInfo(UserPlatformEntity userPlatform) throws UserException {
        String platform_login_id = this.checkLogin();
        if (!userPlatform.getUserPlatformId().equals(platform_login_id)) throw new UserException(USER_TOKEN_ERROR);
        boolean update = userPlatformService.update(new LambdaUpdateWrapper<UserPlatformEntity>()
                .eq(UserPlatformEntity::getUserPlatformId, platform_login_id)
                .set(UserPlatformEntity::getNickName, userPlatform.getNickName())
                .set(UserPlatformEntity::getVia, userPlatform.getVia())
                .set(UserPlatformEntity::getSex, userPlatform.getSex())
                .set(UserPlatformEntity::getName, userPlatform.getName())
        );
        UserEntity user_info = userService.getById(userPlatform.getUserId());
        if (user_info != null) userPlatform.setUser(user_info);
        if (!update) throw new UserException(USER_UPDATE_PLATFORM_INFO_ERROR);
        return true;
    }

    /**
     * 更新实名信息
     *
     * @param user
     * @return
     * @throws UserException
     */
    public boolean updateUserInfo(UserEntity user) throws UserException {
        String platform_login_id = this.checkLogin();
        if (platform_login_id == null) throw new UserException(USER_TOKEN_ERROR);
        UserEntity user_info = userService.getById(user.getUserId());
        if (user_info == null) throw new UserException(ERROR);
        boolean update = userService.update(new LambdaUpdateWrapper<UserEntity>()
                .eq(UserEntity::getUserId, user.getUserId())
                .set(UserEntity::getUserSex, user.getUserSex())
                .set(UserEntity::getUserName, user.getUserName())
                .set(UserEntity::getUserNickName, user.getUserNickName())
                .set(UserEntity::getUserVia, user.getUserVia())
                .set(UserEntity::getUserPwd, user.getUserPwd())
                .set(UserEntity::getIdCard, user.getIdCard())

        );
        if (!update) throw new UserException(USER_UPDATE_REAL_NAME_INFO_ERROR);
        return true;
    }


}
